package com.bestcem.xm.survey.grpc.client;

import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.bp.grpc.v1.base.Code;
import com.bestcem.bp.grpc.v1.base.Page;
import com.bestcem.bp.xm.user.grpc.v1.services.*;
import com.bestcem.xm.common.core.constant.Constants;
import com.bestcem.xm.common.core.constant.GrpcClientNames;
import com.bestcem.xm.component.cache.annotation.XmCache;
import com.bestcem.xm.survey.convert.grpc.SurveyGrpcConvertMapper;
import com.bestcem.xm.survey.grpc.client.dto.GroupDto;
import com.bestcem.xm.survey.grpc.client.dto.OrgInfoDto;
import com.bestcem.xm.survey.grpc.client.dto.UserDto;
import com.bestcem.xm.survey.grpc.client.dto.UserGroupDto;
import com.bestcem.xm.user.grpc.v1.enums.GroupStatusEnum;
import io.grpc.StatusRuntimeException;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class UserGrpcClient {

    @GrpcClient(GrpcClientNames.DS_USER)
    private UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub;

    @GrpcClient(GrpcClientNames.DS_USER)
    private UserGroupServiceGrpc.UserGroupServiceBlockingStub userGroupServiceBlockingStub;

    @GrpcClient(GrpcClientNames.DS_USER)
    private OrgServiceGrpc.OrgServiceBlockingStub orgServiceBlockingStub;

    private final SurveyGrpcConvertMapper grpcConvertMapper;

    public UserGrpcClient(SurveyGrpcConvertMapper grpcConvertMapper) {
        this.grpcConvertMapper = grpcConvertMapper;
    }


    public GroupDto getRootGroupByOrgId(String orgId) {
        GetRootGroupRequest.Builder builder = GetRootGroupRequest.newBuilder();
        builder.setOrgId(orgId);
        try {
            GetRootGroupResponse response = userGroupServiceBlockingStub.getRootGroup(builder.build());
            if (Objects.isNull(response) || Code.ERROR.equals(response.getStatus().getCode())) {
                log.error("[survey] USER getRootGroupByOrgId {} Error; ErrorMsg: {}", orgId, response);
                return null;
            }
            return infoToGroupDTO(response.getGroup());
        } catch (Exception e) {
            log.error("[survey] USER getOrganizationByCode {} Error; ErrorMsg: {}", orgId, e.getMessage(), e);
            return null;
        }
    }

    /**
     * GroupV1 to GroupDTO
     *
     * @param group proto中定义的Group
     * @return 成员组DTO
     * @author <yuming.pan@idiaoyan.com>
     * @date 21:11 2021/8/26
     */
    public static GroupDto infoToGroupDTO(Group group) {
        if (Objects.isNull(group)) {
            return null;
        }
        GroupDto groupDTO = new GroupDto();
        groupDTO.setId(group.getId());
        groupDTO.setAncestors(group.getParentIdsList());
        groupDTO.setParentId(group.getParentId());
        // groupDTO.setRootId(group.getRootId());
        // groupDTO.setRoot(group.getIsRoot());
        groupDTO.setOrgId(group.getOrgId());
        groupDTO.setCode(group.getCode());
        groupDTO.setSeq(group.getSeq());
        groupDTO.setTitle(group.getName());
        groupDTO.setGroupType(group.getTypeValue());
        groupDTO.setGroupLevelId(group.getLevelId());
        groupDTO.setStatus(group.getStatusValue());
        groupDTO.setContact(group.getPhone());
        groupDTO.setEmail(group.getEmail());
        // groupDTO.setChildrenOrder(group.getChildrenOrderList());
        groupDTO.setAdminId(group.getAdminId());
        groupDTO.setAdminName(group.getAdminName());
        return groupDTO;
    }

    //rpc GetGroup(GetGroupRequest) returns (GetGroupResponse) {};

    public GroupDto getGroup(JSONObject param) {
        GetGroupRequest.Builder builder = GetGroupRequest.newBuilder();
        if (!ObjectUtils.isEmpty(param.getString("orgID"))) {
            builder.setOrgId(param.getString("orgID"));
        }
        if (!ObjectUtils.isEmpty(param.getString("code"))) {
            builder.setCode(param.getString("code"));
        }

        try {
            GetGroupResponse response = userGroupServiceBlockingStub.getGroup(builder.build());
            if (Objects.isNull(response) || Code.ERROR.equals(response.getStatus().getCode())) {
                log.error("[survey] USER getGroup {} Error; ErrorMsg: {}", param, response);
                return null;
            }
            return infoToGroupDto(response.getGroup());
        } catch (Exception e) {
            log.error("[survey] USER ex getGroup {} Error; ErrorMsg: {}", param, e.getMessage(), e);
            return null;
        }
    }


    public List<GroupDto> listGroup(JSONObject param) {
        SearchGroupsRequest.Builder builder = SearchGroupsRequest.newBuilder();
        GroupCondition.Builder groupBuilder = GroupCondition.newBuilder();
        if (!ObjectUtils.isEmpty(param.getString("orgID"))) {
            groupBuilder.setOrgId(param.getString("orgID"));
        }
        if (!ObjectUtils.isEmpty(param.getString("code"))) {
            groupBuilder.setCode(param.getString("code"));
        }
        if (!ObjectUtils.isEmpty(param.getString("groupLevelID"))) {
            groupBuilder.setLevelId(param.getString("groupLevelID"));
        }
        Object status = param.get("status");
        if (!ObjectUtils.isEmpty(status)) {
            groupBuilder.setStatus(GroupStatusEnum.GroupStatus.forNumber((Integer) status));
        }

        builder.setGroup(groupBuilder.build());
        try {
            SearchGroupsResponse response = userGroupServiceBlockingStub.searchGroups(builder.build());
            if (Objects.isNull(response) || Code.ERROR.equals(response.getStatus().getCode())) {
                log.error("[survey] USER listGroup {} Error; ErrorMsg: {}", param, response);
                return null;
            }
            return responseToGroupDtoList(response);
        } catch (Exception e) {
            log.error("[survey] USER ex listGroup {} Error; ErrorMsg: {}", param, e.getMessage(), e);
            return null;
        }
    }

    private GroupDto infoToGroupDto(Group group) {
        if (Objects.isNull(group)) {
            return null;
        }
        GroupDto groupDTO = new GroupDto();
        groupDTO.setId(group.getId());
        // groupDTO.setAncestors(group.getAncestorsList());
        groupDTO.setParentId(group.getParentId());
        // groupDTO.setRootId(group.getRootId());
        // groupDTO.setRoot(group.getIsRoot());
        groupDTO.setOrgId(group.getOrgId());
        groupDTO.setCode(group.getCode());
        groupDTO.setSeq(group.getSeq());
        groupDTO.setTitle(group.getName());
        groupDTO.setGroupType(group.getTypeValue());
        groupDTO.setGroupLevelId(group.getLevelId());
        groupDTO.setStatus(group.getStatusValue());
        groupDTO.setContact(group.getPhone());
        groupDTO.setEmail(group.getEmail());
        // groupDTO.setChildrenOrder(group.getChildrenOrderList());
        groupDTO.setAdminId(group.getAdminId());
        groupDTO.setAdminName(group.getAdminName());
        return groupDTO;
    }

    private List<GroupDto> responseToGroupDtoList(SearchGroupsResponse response) {
        List<Group> groupList = response.getGroupsList();
        List<GroupDto> groupDtoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(groupList)) {
            groupList.forEach(group -> {
                GroupDto groupDTO = infoToGroupDto(group);
                if (Objects.nonNull(groupDTO)) {
                    groupDtoList.add(groupDTO);
                }
            });
        }
        return groupDtoList;
    }

    @XmCache
    public UserDto getUser(String userId) {
        GetUserByIdRequest.Builder builder = GetUserByIdRequest.newBuilder();
        builder.setId(userId);
        try {
            GetUserByIdResponse response = userServiceBlockingStub.getUserById(builder.build());
            if (Objects.isNull(response) || response.getStatus().getCodeValue() != 0) {
                log.error("[survey] USER getUser {} Error; ErrorMsg: {}", userId, response);
                return null;
            }
            return responseToUserDto(response);
        } catch (Exception e) {
            log.error("[survey] USER getUser {} Error; ErrorMsg: {}", userId, e.getMessage(), e);
            return null;
        }
    }

    public List<UserDto> listUserByOrgId(String orgId) {
        ListUsersByFilterRequest.Builder builder = ListUsersByFilterRequest.newBuilder();
        UserCondition.Builder userBuilder = UserCondition.newBuilder();
        userBuilder.setOrgId(orgId);
        builder.setUser(userBuilder.buildPartial());
        try {
            ListUsersByFilterResponse response = userServiceBlockingStub.listUsersByFilter(builder.build());
            if (Objects.isNull(response) || response.getStatus().getCodeValue() != 0) {
                log.error("[survey] USER listUserByOrgId {} Error; ErrorMsg: {}", orgId, response);
                return new ArrayList<>();
            }
            return responseToUserDtoList(response);
        } catch (Exception e) {
            log.error("[survey] USER listUserByOrgId {} Error; ErrorMsg: {}", orgId, e.getMessage(), e);
            return new ArrayList<>();
        }
    }

    public OrgInfoDto getOrganization(String orgId) {
        GetOrgByIdOrCodeRequest.Builder builder = GetOrgByIdOrCodeRequest.newBuilder();
        builder.setId(orgId);
        try {
            GetOrgByIdOrCodeResponse response = orgServiceBlockingStub.getOrgByIdOrCode(builder.buildPartial());
            if (Objects.isNull(response) || response.getStatus().getCodeValue() != 0) {
                log.error("[survey] USER getOrganization {} Error; ErrorMsg: {}", orgId, response);
                return new OrgInfoDto();
            }
            /*Organization organization = response.getOrganization();
            OrgInfoDto orgInfoDTO = new OrgInfoDto();
            orgInfoDTO.setId(organization.getId());
            orgInfoDTO.setIndustryId(organization.getIndustryId());
            orgInfoDTO.setIsDeliverCheck(organization.getIsDeliverCheck());
            orgInfoDTO.setSkin(organization.getSkin());
            orgInfoDTO.setCode(organization.getCode());
            orgInfoDTO.setFooter(organization.getFooterValue());
            return orgInfoDTO;*/
            return grpcConvertMapper.toOrgInfoDto(response.getOrg());
        } catch (Exception e) {
            log.error("[survey] USER getOrganization {} Error; ErrorMsg: {}", orgId, e.getMessage(), e);
            return new OrgInfoDto();
        }
    }

    /**
     * 获取用户角色信息
     *
     * @param userId 用户id
     * @param roleId roleId
     * @return User info
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/11/4 20:30
     */
    public List<UserRole> getUserRole(String userId, String roleId) {
        ListUserRolesRequest.Builder builder = ListUserRolesRequest.newBuilder();
        if (userId != null) {
            builder.setUserId(userId);
        }
        builder.setRoleId(roleId);
        try {
            ListUserRolesResponse response = userServiceBlockingStub.listUserRoles(builder.build());
            if (Objects.isNull(response) || response.getStatus().getCodeValue() != 0) {
                log.error("[survey] USER getUser {} Error; ErrorMsg: {}", userId, response);
                return new ArrayList<>();
            }
            return response.getRolesList();
        } catch (Exception e) {
            log.error("[survey] USER getUser {} Error; ErrorMsg: {}", userId, e.getMessage(), e);
            return new ArrayList<>();
        }
    }

    public List<UserDto> responseToUserDtoList(ListUsersByFilterResponse response) {
        List<UserDto> userDtoList = new ArrayList<>();
        List<User> users = response.getUsersList();
        if (!CollectionUtils.isEmpty(users)) {
            for (User user : users) {
                UserDto userDTO = grpcConvertMapper.toUserDto(user);
                if (Objects.nonNull(userDTO)) {
                    userDtoList.add(userDTO);
                }
            }
        }
        return userDtoList;
    }

    public UserDto responseToUserDto(GetUserByIdResponse response) {
        User user = response.getUser();
        return grpcConvertMapper.toUserDto(user);
    }

    public Organization getByIdOrCode(String orgId, String orgCode) {
        GetOrgByIdOrCodeRequest.Builder builder = GetOrgByIdOrCodeRequest.newBuilder();
        if (StringUtils.isNotEmpty(orgId)) {
            builder.setId(orgId);
        }
        if (StringUtils.isNotEmpty(orgCode)) {
            builder.setCode(orgCode);
        }
        try {
            GetOrgByIdOrCodeResponse response = orgServiceBlockingStub.getOrgByIdOrCode(builder.build());
            if (Code.OK_VALUE == response.getStatus().getCodeValue()) {
                if (log.isInfoEnabled()) {
                    log.info("[survey] user返回：{}", response.getOrg());
                }
                return response.getOrg();
            }
        } catch (Exception e) {
            log.error("[survey] 调用user接口[查询机构信息]失败 orgId:{} ", orgId, e);
        }
        return null;
    }

    /**
     * 获取单个激活的Group
     *
     * @param id id
     * @return Group
     */
    public GroupDto getGroup(String id) {
        if (!ObjectId.isValid(id)) {
            return null;
        }
        GetGroupRequest.Builder builder = GetGroupRequest.newBuilder();
        builder.setId(id);
        GetGroupResponse response = userGroupServiceBlockingStub.getGroup(builder.build());

        if (!Code.OK.equals(response.getStatus().getCode())) {
            if (log.isErrorEnabled()) {
                log.error("[Survey] 调用 getGroup 接口失败: dto: {}", response);
            }
            return new GroupDto();
        }

        Group group = response.getGroup();
        if (!GroupStatusEnum.GroupStatus.ACTIVATED.equals(group.getStatus())) {
            if (log.isErrorEnabled()) {
                log.error("组织：{} 已失效", response.getGroup());
            }
            return new GroupDto();
        }
        return this.groupToDTO(response.getGroup());
    }

    /**
     * group to DTO
     *
     * @param group
     * @return
     */
    private GroupDto groupToDTO(Group group) {
        GroupDto dto = new GroupDto();
        if (ObjectUtil.isEmpty(group)) {
            return dto;
        }
        dto.setAdminId(group.getAdminId());
        dto.setAdminName(group.getAdminName());
        dto.setAncestors(group.getParentIdsList());
        dto.setCode(group.getCode());
        dto.setContact(group.getPhone());
        dto.setEmail(group.getEmail());
        dto.setGroupLevelId(group.getLevelId());
        dto.setGroupType(group.getTypeValue());
        dto.setId(group.getId());
        dto.setOrgId(group.getOrgId());
        dto.setParentId(group.getParentId());
        dto.setSeq(group.getSeq());
        dto.setStatus(group.getStatusValue());
        dto.setTitle(group.getName());
        return dto;
    }

    public List<Map<String, String>> getGrouplevels(String orgId) {
        ListGroupLevelsRequest.Builder builder = ListGroupLevelsRequest.newBuilder();
        builder.setOrgId(orgId);
        ListGroupLevelsResponse response = userGroupServiceBlockingStub.listGroupLevels(builder.build());
        if (!Code.OK.equals(response.getStatus().getCode())) {
            log.error("[Survey] 调用 getGrouplevels 接口失败: dto: {}", response);
            return Collections.emptyList();
        }

        return response.getLevelsList().stream().map(it -> {
            Map<String, String> map = new HashMap<>();
            map.put("id", it.getId());
            map.put("title", it.getName());
            return map;
        }).collect(Collectors.toList());
    }

    /**
     * 通过查询条件批量一次性获取所有符合条件的UserGroup
     *
     * @param rootGroupId
     * @param userId
     * @return 用户和组的关联DTO
     * @author <yuming.pan@idiaoyan.com>
     * @date 16:41 2021/8/27
     */
    @Nullable
    public List<UserGroupDto> listUserGroup(String rootGroupId, String userId) {
        ListUserGroupsRequest.Builder builder = ListUserGroupsRequest.newBuilder();
        builder.setRootGroupId(rootGroupId);
        builder.setUserId(userId);
        try {
            ListUserGroupsResponse response = userGroupServiceBlockingStub.listUserGroups(builder.build());
            if (Objects.isNull(response) || Code.ERROR.equals(response.getStatus().getCode())) {
                log.error("[survey] USER listUserGroup ，groupId：{} Error; ErrorMsg: {}", rootGroupId, response);
                return null;
            }
            return responseToUserGroupDTOList(response);
        } catch (Exception e) {
            log.error("[survey] USER listUserGroup,groupId： {} Error; ErrorMsg: {}", rootGroupId, e.getMessage(), e);
            return null;
        }
    }

    /**
     * UserGroupSearchResponse to List<UserGroupDTO>
     *
     * @param response 通过查询条件批量一次性获取所有符合条件的UserGroup的response
     * @return 用户和组的关联集合
     * @author <yuming.pan@idiaoyan.com>
     * @date 16:26 2021/8/27
     */
    public static List<UserGroupDto> responseToUserGroupDTOList(ListUserGroupsResponse response) {
        List<UserRelateGroup> userGroupList = response.getGroupsList();
        List<UserGroupDto> userGroupDtoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(userGroupList)) {
            userGroupList.forEach(userGroup -> {
                if (Objects.nonNull(userGroup)) {
                    UserGroupDto userGroupDTO = infoToUserGroupDTO(userGroup);
                    userGroupDtoList.add(userGroupDTO);
                }
            });
        }
        return userGroupDtoList;
    }

    /**
     * UserGroup to UserGroupDTO
     *
     * @param userGroup proto中定义的UserGroup
     * @return 用户和组的关联DTO
     * @author <yuming.pan@idiaoyan.com>
     * @date 16:37 2021/8/27
     */
    private static UserGroupDto infoToUserGroupDTO(UserRelateGroup userGroup) {
        if (Objects.isNull(userGroup)) {
            return null;
        }
        UserGroupDto userGroupDTO = new UserGroupDto();
        userGroupDTO.setId(userGroup.getId());
        userGroupDTO.setRootGroupId(userGroup.getRootGroupId());
        userGroupDTO.setUserId(userGroup.getUserId());
        userGroupDTO.setGroupId(userGroup.getGroupId());
        return userGroupDTO;
    }

    /**
     * 通过 root_group_id 获取该门店层级结构和子门店层级结构
     *
     * @param rootGroupId     root_group_id
     * @param includeInactive 是否包含失效节点
     * @return 层级结构
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/8/30 17:09
     */
    public GroupNode getGroupTreeByRootGroupId(String rootGroupId, boolean includeInactive) {
        GetGroupTreeByGroupIdRequest.Builder builder = GetGroupTreeByGroupIdRequest.newBuilder();
        builder.setGroupId(rootGroupId);
        builder.setIncludeInactive(includeInactive);
        try {
            GetGroupTreeByGroupIdResponse response = userGroupServiceBlockingStub.getGroupTreeByGroupId(builder.build());
            if (Objects.isNull(response) || Code.ERROR.equals(response.getStatus().getCode())) {
                log.error("[Deliver] USER getGroupTreeByRootGroupId {}-{} Error; ErrorMsg: {}", rootGroupId, includeInactive, response);
                return null;
            }
            return response.getTree();
        } catch (Exception e) {
            log.error("[Deliver] USER getGroupTreeByRootGroupId {}-{} Error; ErrorMsg: {}", rootGroupId, includeInactive, e.getMessage(), e);
            return null;
        }
    }

    public List<Group> listGroups(String orgId, String groupCode, List<Integer> statusList) {
        Page pageParam = Page.newBuilder().setPage(1).setSize(10000).build();
        GroupCondition groupCondition = GroupCondition.newBuilder().setOrgId(orgId).setCode(groupCode).build();
        ListGroupsRequest request = ListGroupsRequest.newBuilder()
                .setGroup(groupCondition)
                .setPage(pageParam)
                .addAllStatusesValue(statusList).build();
        ListGroupsResponse response;
        try {
            response = userGroupServiceBlockingStub.listGroups(request);
        } catch (StatusRuntimeException e) {
            log.error("【联系人】搜索用户组列表失败, request: {}", request, e);
            throw new RuntimeException("【联系人】搜索用户组列表失败, request: " + request);
        }
        if (response.getStatus().getCodeValue() != Constants.SUCCESS) {
            log.error("【联系人】搜索用户组列表失败, request: {}, response: {}", request, response);
            throw new RuntimeException("【联系人】搜索用户组列表失败, request: " + request);
        }
        return response.getGroupsList();
    }
}
